//    1.作为输入参数的闭包可能会有不同的 trait 约束，这取决于它们如何使用。
    // 该函数将闭包作为参数并调用它
    fn apply<F>(f: F) where
        F: FnOnce() {
            // ^试一试：将 `FnOnce` 换成 `Fn` 或 `FnMut`。
        f();
    }
    // 输入闭包,返回一个'i32'整型的函数
    fn apply_to_3<F>(f: F) -> i32 where
        F: Fn(i32) -> i32 {
        f(3)
    }

    // 2.作为输出参数的闭包,只支持返回具体类型非泛型,那么只有使用impl trait返回闭包
    fn create_fn() -> impl Fn() {
        let text = "Fn".to_owned();
        move || println!("This is a: {}", text)
    }
    fn create_fnmut() -> impl FnMut() {
        let text = "FnMut".to_owned();
        move || println!("This is a: {text}")
    }
    fn create_fnonce() -> impl FnOnce() {
        let text = "FnOnce".to_owned();
        move || println!("This is a: {text}")
    }
fn main() {
    // 1.作为输入参数的闭包可能会有不同的 trait 约束，这取决于它们如何使用。
    let greeting = "hello";
    // 不可复制的类型。
    // 'to_owned' 创建一个具有所有权的 `String`。
    let mut farewell = "goodbye".to_owned();
    // 捕获2个变量：通过引用捕获 `greeting`，通过值捕获 `farewell`。
    let diary = ||{
        // `greeting` 是通过引用捕获的，故需要闭包是 `Fn`。
        println!("I said {}.", greeting);
        // 下文改变了 `farewell` ，因而要求闭包通过可变引用来捕获它。
        // 
        farewell.push_str("!!!");
        println!("Then I screamed {}.", farewell);
        println!("Now I can sleep. zzzzz");
        // 手动调用 `drop` 来销毁 `farewell`。
        // 现在需要 `FnOnce`，因为变量只能被消费一次。
        std::mem::drop(farewell);
    };

    apply(diary);
    // println!("{farewell}");
    
    // 闭包'double'满足`apply_to_3`的trait约束
    let double = |x| 2 * x;
    println!("3 doubled: {}", apply_to_3(double));

    // 2.作为输出参数的闭包,只支持返回具体类型非泛型,那么只有使用impl trait返回闭包
    let fn_plain = create_fn();
    let mut fn_mut = create_fnmut();
    let fn_once = create_fnonce();

    fn_plain();
    fn_mut();
    fn_once();
}
